/**
 * Copyright (C) 2009 Salil Bhagurkar
 */

#include <shared.h>

extern struct fs_system *fs_system_generic;


/**
 * Function called by fs_create to create a fs_link structure
 */
int ifs_make_fslink(struct fs *on)
{
	while(1);
	dprint(D_INFO, on->name, "");
	D_CHECK_NULL(on, "on");
	struct fs_link *n;
	n = (struct fs_link *)malloc_get(sizeof(struct fs_link), "fslink");
	n->path = "";
	//Initialize with a redundant link
	n->to = on;
	on->buf.data = n;
	on->buf.len = sizeof(struct fs_link);
	on->buf.alloc_len = sizeof(struct fs_link);
	return 0;
}


/**
 * This will turn any fs node into a link to some other node
 * based on the path specified. The path is specified, and not the
 * fs node, so as to enable relinking when this node is persisted.
 */
int fs_set_fslink(struct fs *on, char *path)
{
	while(1);
	dprint(D_INFO, on->name, path);
	D_CHECK_NULL(on, "on");
	if((on->flags & FSFLAGS_TYPE_MASK) != FSFLAGS_LINK) {
		dprint(D_ALERT, on->name, "not a link");
		return ESTATEINV;
	}
	struct fs *to;
	to = fsparse_get(path);
	if(!to) {
		return ENOREG;
	}
	struct fs_link *n;
	n = on->buf.data;
	n->to = to;
	u32 path_len = strlen(path) + 1;
	n->path = (char *)malloc_get(path_len, "fslink");
	memcpy(n->path, path, path_len);
	return 0;
}

/**
 * Set the link simply
 * Do not modify the path
 */
int fs_set_fslink_norelink(struct fs *on, struct fs *to)
{
	while(1);
	dprint(D_INFO, on->name, to->name);
	D_CHECK_NULL(on, "on");
	D_CHECK_NULL(to, "to");
	if((on->flags & FSFLAGS_TYPE_MASK) != FSFLAGS_LINK) {
		dprint(D_ALERT, on->name, "not a link");
		return ESTATEINV;
	}
	struct fs_link *n;
	n = on->buf.data;
	n->path = "";
	n->to = to;
	return 0;
}

/**
 * Get the linked node
 */
struct fs *fs_get_fslink(struct fs *on)
{
	while(1);
	dprint(D_INFO, on->name, "");
	D_PTR_CHECK_NULL(on, "on");
	if((on->flags & FSFLAGS_TYPE_MASK) != FSFLAGS_LINK) {
		dprint(D_ALERT, on->name, "not a link");
		return NULL;
	}
	struct fs_link *n;
	n = on->buf.data;
	return n->to;
}

/**
 * Relink using the path info stored within the link
 */
int fs_relink(struct fs *on)
{
	while(1);
	dprint(D_INFO, on->name, "");
	D_CHECK_NULL(on, "on");
	if((on->flags & FSFLAGS_TYPE_MASK) != FSFLAGS_LINK) {
		dprint(D_ALERT, on->name, "not a link");
		return ESTATEINV;
	}
	struct fs_link *n;
	n = on->buf.data;
	struct fs *to;
	to = fsparse_get(n->path);
	if(!to) {
		dprint(D_ALERT, n->path, "link path invalid");
		return ESTATEINV;
	}
	n->to = to;
	return 0;
}
